package com.gitee.wsl.text.buffer.storage

import com.gitee.wsl.struct.generator.VarNameGenerator.Companion.DigitOnes
import com.gitee.wsl.struct.generator.VarNameGenerator.Companion.DigitTens
import com.gitee.wsl.struct.generator.VarNameGenerator.Companion.digits

fun interface GetCharsTrait<in T> {
    fun getChars(src: T, srcBegin: Int, srcEnd: Int, dest: CharArray, destBegin: Int)

    companion object
}

@PublishedApi
internal val charArrayGetCharsTrait =
    GetCharsTrait<CharArray> { src, srcBegin, srcEnd, dest, destBegin ->
        //System.arraycopy(src, srcBegin, dest, destBegin, destBegin + (srcEnd - srcBegin))
        src.copyInto(dest,destBegin,srcBegin,srcEnd)
    }

internal val charSequenceGetCharsTrait =
    GetCharsTrait<CharSequence> { src, srcBegin, srcEnd, dest, destBegin ->
        val length = srcEnd - srcBegin
        for (i in 0 until length) {
            dest[destBegin + i] = src[srcBegin + i]
        }
    }

 object EmptyGetCharsTrait : GetCharsTrait<Unit> {
    override fun getChars(src: Unit, srcBegin: Int, srcEnd: Int, dest: CharArray, destBegin: Int) {
        require(srcBegin == 0 && srcEnd == 0)
    }
}

val GetCharsTrait.Companion.Empty get() = EmptyGetCharsTrait

 object SingleCharGetCharsTrait : GetCharsTrait<Char> {
    override fun getChars(src: Char, srcBegin: Int, srcEnd: Int, dest: CharArray, destBegin: Int) {
        require(srcBegin == 0 && srcEnd == 1)
        dest[destBegin] = src
    }
}

val GetCharsTrait.Companion.SingleChar get() = SingleCharGetCharsTrait


fun StringBuilder.getChars(srcBegin: Int, srcEnd: Int, dst: CharArray, destBegin: Int){
    var dstOff = destBegin
    var srcOff = srcBegin
    val len = srcEnd - srcBegin
    for (i in 0 until len) {
        dst[dstOff++] = (get(srcOff++).code and 0xff).toChar()
    }
}

fun String.getChars(srcBegin: Int, srcEnd: Int, dst: CharArray, destBegin: Int){
    var dstOff = destBegin
    var srcOff = srcBegin
    val len = srcEnd - srcBegin
    for (i in 0 until len) {
        dst[dstOff++] = (get(srcOff++).code and 0xff).toChar()
    }
}

fun Long.getChars(dst: CharArray, destBegin: Int){
    getCharsFromLong(this,destBegin,dst)
}

// moved from Long.getChars
internal fun getCharsFromLong(i: Long, index: Int, buf: CharArray) {
    var i = i
    var q: Long
    var r: Int
    var charPos = index
    var sign = 0.toChar()

    if (i < 0) {
        sign = '-'
        i = -i
    }

    // Get 2 digits/iteration using longs until quotient fits into an int
    while (i > Int.MAX_VALUE) {
        q = i / 100
        // really: r = i - (q * 100);
        r = (i - ((q shl 6) + (q shl 5) + (q shl 2))).toInt()
        i = q
        buf[--charPos] = DigitOnes[r]
        buf[--charPos] = DigitTens[r]
    }

    // Get 2 digits/iteration using ints
    var q2: Int
    var i2 = i.toInt()
    while (i2 >= 65536) {
        q2 = i2 / 100
        // really: r = i2 - (q * 100);
        r = i2 - ((q2 shl 6) + (q2 shl 5) + (q2 shl 2))
        i2 = q2
        buf[--charPos] = DigitOnes[r]
        buf[--charPos] = DigitTens[r]
    }

    // Fall thru to fast mode for smaller numbers
    // assert(i2 <= 65536, i2);
    while (true) {
        q2 = (i2 * 52429) ushr (16 + 3)
        r = i2 - ((q2 shl 3) + (q2 shl 1)) // r = i2-(q2*10) ...
        buf[--charPos] = digits[r]
        i2 = q2
        if (i2 == 0) {
            break
        }
    }
    if (sign.code != 0) {
        buf[--charPos] = sign
    }
}